import { login, logout, getInfo } from '@/api/acl/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter,constantRoutes,allAsyncRoutes,anyRoutes } from '@/router'
import router from '@/router'

// 引入lodash中的深拷贝
import cloneDeep from 'lodash/cloneDeep'
const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',
    //权限相关的数据
    buttons:[],//和用户按钮权限相关的权限数据
    roles:[],//和用户角色相关的权限数据
    routes:[],//和用户相关的所有路由配置权限,这个数组是后面用户形成的最终的路由数组,里面是路由对象,不是字符串
    asyncRoutes:[],//和用户相关的所有异步路由数组,这个数组里面也是路由对象,不是字符串


  }
}


// 定义一个函数,这个函数专门根据用户防腐的routes路由name字符串数组过滤出用户真正的那一步路由数组
function filterMyAsyncRoutes(allAsyncRoutes,routeNames){
  const myAsyncRoutes=  allAsyncRoutes.filter((item)=>{
    // 判断一级路由
    if(routeNames.indexOf(item.name) != -1){
      // 判断二级路由,使用递归去操作
      if(item.children && item.children.length){
        // 递归查找符合条件的二级路由,然后把二级路由整体改为符合条件的二级路由
        item.children= filterMyAsyncRoutes(item.children,routeNames)
      }
      return true
    }
  })
  return myAsyncRoutes
}





const state = getDefaultState()
// 修改state唯一的地方
const mutations = {
  // 重置state
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  // 设置token
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  // SET_NAME: (state, name) => {
  //   state.name = name
  // },
  // SET_AVATAR: (state, avatar) => {
  //   state.avatar = avatar
  // }
  
  SET_USERINFO:(state,userInfo)=>{
    state.name=userInfo.name
    state.avatar=userInfo.avatar
    state.buttons=userInfo.buttons
    state.roles=userInfo.roles
  },
  // 获取用户自己的异步路由数组,存储在state中
  SET_ROUTES:(state,myAsyncRoutes)=>{
    state.asyncRoutes=myAsyncRoutes//把自己过滤出来的异步路由保存起来
    //使用常量路由拼接自己的异步路由和任意路由,形成自己的最终的所有路由数组
    state.routes=constantRoutes.concat(myAsyncRoutes,anyRoutes)
    //现在目前的路由当中只有常量路由,目前我们需要将路由器当中配的路由动态的改变成我们最终的路由
    // 动态往路由器中添加新的路由
    router.addRoutes([...myAsyncRoutes,anyRoutes])//动态的把自己的异步路由和任意路由注册到路由器内部的路由数组当中
  }


}
//---------------------计算异步路由-------------
// 定义一个函数,目的有两个,第一个是过滤出需要展示的异步路由,第二个因为服务器返回的数组里面是字符串,要计算成路由规则的数组的样子,返回
function filterAllAsyncRoutes(allAsyncRoutes,routesName){
  return allAsyncRoutes.filter((item)=>{
    // 判断当前路由当中的name属性值时候在routes中出现
    if(routesName.indexOf(item.name) != -1){
      // 判断当前路由是否包含子路由
      if(item.children && item.children.length){
        item.children=filterAllAsyncRoutes(item.children,routesName)
      }
      return true;
    }
  })
}

//--------------------------------------------------
// actions
const actions = {
  //登录业务
  async login({ commit }, userInfo) {
    const { username, password } = userInfo;
    let result = await login({ username: username.trim(), password: password });
    if (result.code == 20000 || result.code == 200) {
      //提交mutation，修改Vuex中state的token字段
      commit("SET_TOKEN", result.data.token);
      //持久化存储
      setToken(result.data.token);
      return "ok";
    } else {
      return Promise.reject(new Error("faile"));
    }
  },

  // get user info获取用户信息(开发后台管理系统权限问题:用户信息)
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      // 调用getInfo函数
      getInfo(state.token).then(response => {
        // 服务器返回的用户信息
        const { data } = response
        // const { name, avatar } = data

        // commit('SET_NAME', name)
        // commit('SET_AVATAR', avatar)
        commit('SET_USERINFO',data)
        // 还要去根据用户返回来的routes(和路由name相关的字符串数组),从所有的异步路由数组当中过滤出用户自己的所有异步路由数组
        //data.routes  字符串数组,字符串是由路由的name值组成的 例如 ['Attr','Trademark']
        commit('SET_ROUTES',filterMyAsyncRoutes(cloneDeep(allAsyncRoutes),data.routes))
        // cloneDeep(allAsyncRoutes) 我们最终要改成这样
        // 因为过滤的时候如果是在数据本身上去过滤,那么过滤完成后秘书局的二级路由就改变了
        // 数据本身的二级路由会被过滤后的二级路由覆盖,想找到就不行了
        // 表现是  先登录其他只有某个二级路由的用户,然后退出,登录admin,那么admin也只有一个二级路由
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout退出登录
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        removeToken() // must remove  token  first
        resetRouter()
        commit('RESET_STATE')
        resolve()
      }).catch(error => {
        reject(error)
      })
      .catch(error => {
        reject(error);
      });
  });
},

  // remove token 移除token
  resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // must remove  token  first
      commit('RESET_STATE')
      resolve()
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

